import { ITimer } from "./ITimer";
import { RepeatTimer, TimerToken, WaitTimer } from "./Timer";

export class TimerManager extends et.Entity {
    private static _Instance: TimerManager;
    public static set Instance(value: TimerManager) {
        this._Instance = value;
    }
    public static get Instance() {
        return this._Instance;
    }
    private readonly removeTimers = new Array<ITimer>();
    private readonly runningTimers = new Set<ITimer>();

    public Tick(dt: number): void {
        for (let timer of this.runningTimers) {
            if (!timer.IsDestory) {
                timer.Tick(dt);
            }
            else {
                this.removeTimers.Add(timer);
            }
        }
        for (let timer of this.removeTimers) {
            this.runningTimers.delete(timer);
        }
        this.removeTimers.length = 0;
    }

    public Wait(time: number, timerToken: TimerToken = null) {
        return new Promise<boolean>((resolve) => {
            let timer = et.ObjectPool.Instance.fetch(WaitTimer);
            timer.IsDestory = false;
            this.runningTimers.add(timer);
            timer.Set(() => {
                resolve(true);
                et.ObjectPool.Instance.recycle(timer);
                timer.IsDestory = true;
            }, time);
            if (timerToken != null) {
                timerToken.PasueAction = (() => {
                    this.runningTimers.delete(timer);
                }).bind(this);
                timerToken.ResumeAction = (() => {
                    if (!this.runningTimers.has(timer))
                        this.runningTimers.add(timer);
                }).bind(this);
                timerToken.StopAction = (() => {
                    resolve(false);
                    et.ObjectPool.Instance.recycle(timer);
                    timer.IsDestory = true;
                }).bind(this);
            }
        });
    }
    public Interval(intervalAction: () => void, interval: number, repeatCount: number = 0, timerToken: TimerToken = null) {
        return new Promise<boolean>((resolve) => {
            let repeatTimer = et.ObjectPool.Instance.fetch(RepeatTimer);
            repeatTimer.IsDestory = false;
            this.runningTimers.add(repeatTimer);
            let count = 0;
            repeatTimer.Set(() => {
                intervalAction();
                if (repeatCount > 0) {
                    count++;
                    if (count >= repeatCount) {
                        resolve(true);
                        et.ObjectPool.Instance.recycle(repeatTimer);
                        repeatTimer.IsDestory = true;
                    }
                }

            }, interval);

            if (timerToken != null) {
                timerToken.PasueAction = (() => {
                    this.runningTimers.delete(repeatTimer);
                }).bind(this);
                timerToken.ResumeAction = (() => {
                    if (!this.runningTimers.has(repeatTimer))
                        this.runningTimers.add(repeatTimer);
                }).bind(this);
                timerToken.StopAction = (() => {
                    resolve(false);
                    et.ObjectPool.Instance.recycle(repeatTimer);
                    repeatTimer.IsDestory = true;
                }).bind(this);
            }
        });
    }
    public WaitFrame(frameCount: number, timerToken: TimerToken = null) {
        return new Promise<boolean>((resolve) => {
            if (frameCount < 1) {
                console.error("frameCount小于1!");
                resolve(false);
            }
            let repeatTimer = et.ObjectPool.Instance.fetch(RepeatTimer);
            repeatTimer.IsDestory = false;
            this.runningTimers.add(repeatTimer);
            let count = 0;
            repeatTimer.Set(() => {
                count++;
                if (count >= frameCount) {
                    resolve(true);
                    et.ObjectPool.Instance.recycle(repeatTimer);
                    repeatTimer.IsDestory = true;
                }
            }, 0);

            if (timerToken != null) {
                timerToken.PasueAction = (() => {
                    this.runningTimers.delete(repeatTimer);
                }).bind(this);
                timerToken.ResumeAction = (() => {
                    if (!this.runningTimers.has(repeatTimer))
                        this.runningTimers.add(repeatTimer);
                }).bind(this);
                timerToken.StopAction = (() => {
                    resolve(false);
                    et.ObjectPool.Instance.recycle(repeatTimer);
                    repeatTimer.IsDestory = true;
                }).bind(this);
            }
        });
    }
    public WaitUntil(callBack: () => boolean, timerToken: TimerToken = null, checkInterval = 0) {
        return new Promise<boolean>((resolve) => {
            let repeatTimer = et.ObjectPool.Instance.fetch(RepeatTimer);
            repeatTimer.IsDestory = false;
            this.runningTimers.add(repeatTimer);

            repeatTimer.Set(() => {
                if (callBack()) {
                    resolve(true);
                    et.ObjectPool.Instance.recycle(repeatTimer);
                    repeatTimer.IsDestory = true;
                }
            }, checkInterval);

            if (timerToken != null) {
                timerToken.PasueAction = (() => {
                    this.runningTimers.delete(repeatTimer);
                }).bind(this);
                timerToken.ResumeAction = (() => {
                    if (!this.runningTimers.has(repeatTimer))
                        this.runningTimers.add(repeatTimer);
                }).bind(this);
                timerToken.StopAction = (() => {
                    resolve(false);
                    et.ObjectPool.Instance.recycle(repeatTimer);
                    repeatTimer.IsDestory = true;
                }).bind(this);
            }
        });
    }
    public CurrentMilliseconds(): number {
        return new Date().getTime();
    }

    public CurrentSeconds(): number {
        return Number(this.CurrentMilliseconds() / 1000);
    }
}
@et.objectSystem(TimerManager)
class TimerManagerAwakeSystem extends et.AwakeSystem<TimerManager>{
    awake(self: TimerManager): void {
        TimerManager.Instance = self;
    }
}